"""
This is simply a cut down Pmw scrolled frame.
All Pmw stuff taken out so its pure Tk.
"""

from Tkinter import SUNKEN, NSEW, HORIZONTAL, VERTICAL
from Tkinter import Frame, Scrollbar

class ScrolledFrame(Frame):
    """
    """

    def __init__(self, parent = None, **kw):
        """
        """
        Frame.__init__(self, parent)

        self._enclosing = Frame(self, width = 640, height = 480, relief = SUNKEN, borderwidth = 2)
        self._enclosing.grid(row = 2, column = 2, sticky = NSEW)

        self.grid_rowconfigure(2, weight = 1, minsize = 0)
        self.grid_columnconfigure(2, weight = 1, minsize = 0)

        self._horiz_scrollbar = Scrollbar (self, orient=HORIZONTAL, command=self.xview)
        self._horiz_scrollbar.grid(row = 4, column = 2, sticky = NSEW)
        self.grid_rowconfigure(3, minsize = 2)
        
        self._vert_scrollbar = Scrollbar (self, orient=VERTICAL, command=self.yview)
        self._vert_scrollbar.grid(row = 2, column = 4, sticky = NSEW)
        self.grid_columnconfigure(3, minsize = 2)

        self.scroll_timer = None
        self._scroll_recurse = 0
        self.start_x = 0
        self.start_y = 0

        self._frame = Frame(self._enclosing)

        self._frame.bind('<Configure>', self._reposition)
        self._enclosing.bind('<Configure>', self._reposition)

        self._horiz_scrollbar.set(0.0, 1.0)
        self._vert_scrollbar.set(0.0, 1.0)

    def destroy(self):
        """
        """
        if self.scroll_timer is not None:
            self.after_cancel(self.scroll_timer)
            self.scroll_timer = None

    def interior(self):
        """
        """
        return self._frame

    def reposition(self):
        """
        """
        if self.scroll_timer is None:
            self.scroll_timer = self.after_idle(self._scrollBothNow)

    def xview(self, mode = None, value = None, units = None):
        """
        """
        if isinstance(value, basestring):
            value = float(value)
        if mode is None:
            return self._horiz_scrollbar.get()
        elif mode == 'moveto':
            frame_width = self._frame.winfo_reqwidth()
            self.start_x = value * float(frame_width)
        else: # mode == 'scroll'
            enclosing_width = self._enclosing.winfo_width()
            if units == 'units':
                jump = int(enclosing_width * 0.05)
            else:
                jump = enclosing_width
            self.start_x = self.start_x + value * jump

        self.reposition()

    def yview(self, mode = None, value = None, units = None):
        """
        """
        if isinstance(value, basestring):
            value = float(value)
        if mode is None:
            return self._vert_scrollbar.get()
        elif mode == 'moveto':
            frame_height = self._frame.winfo_reqheight()
            self.start_y = value * float(frame_height)
        else: # mode == 'scroll'
            enclosing_height = self._enclosing.winfo_height()
            if units == 'units':
                jump = int(enclosing_height * 0.05)
            else:
                jump = enclosing_height
            self.start_y = self.start_y + value * jump
        self.reposition()

    def _reposition(self, event):
        """
        """
        self.reposition()

    def _getxview(self):
        """
        """
        enclosing_width = self._enclosing.winfo_width()
        frame_width = self._frame.winfo_reqwidth()
        if frame_width <= enclosing_width:
            self.start_x = 0
            endscroll_x = 1.0
        else:
            if self.start_x + enclosing_width > frame_width:
                self.start_x = frame_width - enclosing_width
                endscroll_x = 1.0
            else:
                if self.start_x < 0:
                    self.start_x = 0
                endscroll_x = (self.start_x + enclosing_width) / float(frame_width)
        self._frame.place(x = -self.start_x, relwidth = '')
        return (self.start_x / float(frame_width), endscroll_x)

    def _getyview(self):
        """
        """
        enclosing_height = self._enclosing.winfo_height()
        frame_height = self._frame.winfo_reqheight()
        if frame_height <= enclosing_height:
             self.start_y = 0
             endscroll_y = 1.0
        else:
             if self.start_y + enclosing_height > frame_height:
                self.start_y = frame_height - enclosing_height
                endscroll_y = 1.0
             else:
                if self.start_y < 0:
                    self.start_y = 0
                endscroll_y = (self.start_y + enclosing_height) / float(frame_height)
        self._frame.place(y = -self.start_y, relheight = '')
        return (self.start_y / float(frame_height), endscroll_y)

    def _scrollBothNow(self):
        """
        """
        self.scroll_timer = None
        self._scroll_recurse = self._scroll_recurse + 1
        self.update_idletasks()
        self._scroll_recurse = self._scroll_recurse - 1
        if self._scroll_recurse != 0:
            return
        xview = self._getxview()
        yview = self._getyview()
        self._horiz_scrollbar.set(xview[0], xview[1])
        self._vert_scrollbar.set(yview[0], yview[1])
